import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Random;
import java.util.Vector;

/**
 * Class holding the structure of the whole environment (RoadMap).
 * @author Jared Lindbl�m
 *
 */
public class RoadMap {
	private HashMap<String, Intersection> intersections;
	private HashMap<String, Road> roads;
	private Vector<Vehicle> vehicles;
	private String name;
	private Metric metric;
	//FileWriter fstream;
	//BufferedWriter out;
	String strLine;
	FileInputStream sourceFile;
	BufferedReader bufferedInDataStream;

	/**
	 * Constructor. We probably won't use this, but it allows us to 
	 * specify the initial size of the hash-maps.
	 * @param name				The name of the road.
	 * @param numIntersections	The number of intersections in the map.
	 * @param numRoads			The number of roads in the map.
	 * @throws IOException 
	 */
	public RoadMap(String name, int numIntersections, int numRoads) throws IOException {
		this.name = name;
		intersections = new HashMap<String, Intersection>(numIntersections);
		roads = new HashMap<String, Road>(numRoads);
		vehicles = new Vector<Vehicle>();
		//fstream = new FileWriter("inputs.txt");
		//out = new BufferedWriter(fstream);
		
		//metric = new Metric(1.0, 1.0);
	}

	/**
	 * Constructor.
	 * @param name	The name of the road.
	 * @throws IOException 
	 */
	public RoadMap(String name) throws IOException {
		this.name = name;
		intersections = new HashMap<String, Intersection>();
		roads = new HashMap<String, Road>();
		vehicles = new Vector<Vehicle>();
		//fstream = new FileWriter("inputs.txt");
		//out = new BufferedWriter(fstream);
		sourceFile = new FileInputStream("inputs.txt");
		DataInputStream inDataStream = new DataInputStream(sourceFile);
		bufferedInDataStream = new BufferedReader(new InputStreamReader(inDataStream));
		//metric = new Metric(1.0, 1.0);
	}

	/**
	 * Accessor Method (Name).
	 * @return	The name of the Road Map.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Accessor Method (Intersection).
	 * @param name	The name of the intersection to get.
	 * @return 	The pointer to the object of the intersection requested.
	 */
	public Intersection getIntersection(String name) {
		return intersections.get(name);
	}

	/**
	 * Accessor Method (Road).
	 * @param name	The name of the road to get.
	 * @return	The pointer to the object of the road requested.
	 */
	public Road getRoad(String name) {
		return roads.get(name);
	}
	
	
	/**
	 * Accessor Method (Metric).
	 * @return	The metric of this roadMap.
	 */
	public Metric getMetric() {
		return metric;
	}

	/**
	 * Accessor Method (Vehicles).
	 * @return An array of vehicles in the RoadMap.
	 */
	public Vector<Vehicle> getVehicles() {
		return vehicles;
	}

	/**
	 * Adds an intersection to the Road Map.
	 * @param name				The name of the intersection (key).
	 * @param newIntersection	The new intersection (value).
	 */
	public void addIntersection(String name, Intersection newIntersection) {
		intersections.put(name, newIntersection);
	}

	/**
	 * Adds a road to the Road Map.
	 * @param name		The name of the road (key).
	 * @param newRoad	The new road (value).
	 */
	public void addRoad(String name, Road newRoad) {
		roads.put(name, newRoad);
	}

	/**
	 * Adds a vehicle to the RoadMap randomly
	 * @param name	The name of the vehicle to be created.
	 * @throws IOException 
	 */
	public void addVehicleRandomly(String name) throws IOException {
		Random random = new Random();
		Intersection[] interList = new Intersection[intersections.size()];
		//System.out.println(intersections.size());
		(intersections.values()).toArray(interList);
		int start = random.nextInt(interList.length);
		int end = random.nextInt(interList.length);
		int speed = 30 + random.nextInt(20);
		strLine = bufferedInDataStream.readLine();
		//System.out.println("line"+strLine);
		String[] result = strLine.split(",");
		//out.write(start+","+end+","+speed+"\n");
		vehicles.addElement(new Vehicle(name, interList[Integer.parseInt(result[0])], interList[Integer.parseInt(result[1])], Integer.parseInt(result[2])));
		//vehicles.addElement(new Vehicle(name, interList[0], interList[interList.length-1], 45));
	}
	
	public void addVehicle(Vehicle vehicle) {
		vehicles.addElement(vehicle);
	}
	
	public void addVehicleRandomly(int number) throws IOException{
		for(int i=1; i<=number; i++)
			addVehicleRandomly(Integer.toString(i));
		//out.close();
		bufferedInDataStream.close();
	}
	
	/**
	 * Set Method (Metric Weights)
	 * @param distanceWeight	The weight of the distance.
	 * @param numVehiclesWeight	The weight of the number of vehicles.
	 */
	public void setMetricWeights(double distanceWeight, double numVehiclesWeight) {
		metric = new Metric (distanceWeight, numVehiclesWeight);
	}
	
	/**
	 * Generate sections of roadway
	 * @return	true if all sections were generated without error.
	 */
	public boolean generateSections() {
		boolean success = true;
		
		for (Road road: roads.values()) {
			if (!road.generateSections())
				success = false;
		}
		
		return success;
	}

	/**
	 * Prints out the structure of the Road Map (for debugging).
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		String print = "RoadMap: " + name + "\n\n";
		String printHold = "";

		print = print.concat("\tRoads: (" + roads.size() + " in total)\n\n");

		print = print.concat("\t\tNorth/South:\n\n");
		for (Road road: roads.values()) {
			if (road.getType().equals("North/South"))
				print = print.concat("\t\t\t" + road.toString() + "\n");
			else {
				printHold = printHold.concat("\t\t\t" + road.toString() + "\n"); 
			}
		}

		print = print.concat("\n\t\tEast/West:\n\n" + printHold + "\n");

		print = print.concat("\tIntersections: (" + intersections.size() + " in total)\n\n");
		for (Intersection intersection: intersections.values()) {
			print = print.concat("\t\t" + intersection.toString() + "\n");
		}

		print = print.concat("\n\tVehicles: (" + vehicles.size() + " in total)\n\n");
		for (int i = 0; i < vehicles.size(); i++) {
			print = print.concat("\t\t" + (vehicles.get(i)).toString() + "\n");
		}

		print = print.concat("(end)");
		return print;
	}
	
	//Added by prarthana
		public HashMap<String, Intersection> getIntersections(){
			return intersections;
			
		}
		
		public HashMap<String, Road> getRoads(){
			return roads;
		}
		
		/**
		 * Accessor Method (All Road Sections)
		 * @return	All the road sections in this RoadMap.
		 */
		public Vector<Section> getAllSections() {
			Vector<Section> sectionVector = new Vector<Section>();
			
			Road[] roadArray = getAllRoads();
			for (int i = 0; i < roadArray.length; i++) {
				sectionVector.copyInto(roadArray[i].getSections());
			}
			
			//Section[] sectionArray = new Section[sectionVector.size()];
			//sectionVector.toArray(sectionArray);
			
			return sectionVector;
		}
		
		/**
		 * Accessor Method (All Roads)
		 * @return All the roads in the RoadMap.
		 */
		public Road[] getAllRoads() {
			Road[] roadArray = new Road[roads.size()];
			(roads.values()).toArray(roadArray);
			return roadArray;
		}

}